/**
 * @brief Biblioteca de álgebra de vetores
 *
 * @author Thales Luis Rodrigues Sabino
 * @date   2009
 */


#include "mcMath.h"


using namespace mc;

/**
 * @brief Construtor padrão. Constroi um vetor com o valor t
 *
 * @param t - Valor para ser setado em todas as componentes
 */
template <class T>
vec3<T>::vec3( const T &t ) {
    this->x = t;
    this->y = t;
    this->z = t;
}


/**
* @brief Constrói a partir de um array
*
* @param a - Array para construir o vetor
*/
template <class T>
vec3<T>::vec3( const T *a ) {
    this->x = a[0];
    this->y = a[1];
    this->z = a[2];
}

/**
 * @brief Constrói um vetor explicitamente
 *
 * @param x - Compomente X
 * @param y - Componente Y
 */
template <class T>
vec3<T>::vec3( const T x, const T y, const T z ) {
    this->x = x;
    this->y = y;
    this->z = z;
}

/**
 * @brief Constrói por cópia
 *
 * @param v - Vetor a ser copiado
 */
template <class T>
vec3<T>::vec3( vec2<T> &v ) {
    this->x = v.x;
    this->y = v.y;
    this->z = (T) 0;
}


/**
 * @brief Constrói por cópia
 *
 * @param v - Vetor a ser copiado
 */
template <class T>
vec3<T>::vec3( vec3<T> &v ) {
    this->x = v.x;
    this->y = v.y;
    this->z = v.z;
}


/**
 * @brief Constrói por cópia
 *
 * @param v - Vetor a ser copiado
 */
template <class T>
vec3<T>::vec3( vec4<T> &v ) {
    this->x = v.x;
    this->y = v.y;
    this->z = v.z;
}



/**
 * @brief Operador [] para acesso ao vetor
 *
 * @param i - Índice de acesso
 */
template <class T>
T& vec3<T>::operator [] ( int i ) {
    assert( i >= 0 && i < this->size() );
    return _array[i];
}


/**
 * @brief Operador soma de dois vetores
 *
 * @param v1
 * @param v2
 */
template <class T>
vec3<T>& vec3<T>::operator + ( const vec3<T> &v ) {
    vec3<T> *vr = new vec3<T>();
    vr->x = this->x + v.x;
    vr->y = this->y + v.y;
    vr->z = this->z + v.z;
    return *vr;
}


/**
 * @brief Operador subtração de dois vetores
 *
 * @param v1
 * @param v2
 */
template <class T>
vec3<T>& vec3<T>::operator - ( const vec3<T> &v ) {
    vec3<T> *vr = new vec3<T>();
    vr->x = this->x - v.x;
    vr->y = this->y - v.y;
    vr->z = this->z - v.z;
    return *vr;
}


/**
 * @brief Operador multiplicação das componentes de dois vetores
 *
 * @param v1
 * @param v2
 */
template <class T>
vec3<T>& vec3<T>::operator * ( const vec3<T> &v ) {
    vec3<T> *vr = new vec3<T>();
    vr->x = this->x * v.x;
    vr->y = this->y * v.y;
    vr->z = this->z * v.z;
    return *vr;
}


/**
 * @brief Operador divisão de compomentes de dois vetores
 *
 * @param v1
 * @param v2
 */
template <class T>
vec3<T>& vec3<T>::operator / ( const vec3<T> &v ) {
    vec3<T> *vr = new vec3<T>();
    vr->x = this->x / v.x;
    vr->y = this->y / v.y;
    vr->z = this->z / v.z;
    return *vr;
}


/**
 * @brief Operador de escalamento
 *
 * @param v - Vetor a ser escalado
 * @param s - Fator de escala
 */
template <class T>
vec3<T>& vec3<T>::operator * ( const T s ) {
    vec3<T> *vr = new vec3<T>();
    vr->x = this->x * s;
    vr->y = this->y * s;
    vr->z = this->z * s;
    return *vr;
}


/**
 * @brief Operador de escalamento
 *
 * @param v - Vetor a ser escalado
 * @param s - Fator de escala
 */
template <class T>
vec3<T>& vec3<T>::operator / ( const T s ) {
    vec3<T> *vr = new vec3<T>();
    vr.x = this->x * s;
    vr.y = this->y * s;
    vr.z = this->z * s;
    return *vr;
}


/**
 * @brief Acumulador +=
 *
 * @param v
 */
template <class T>
vec3<T>& vec3<T>::operator += ( const vec3<T> &v ) {
    this->x += v.x;
    this->y += v.y;
    this->z += v.z;
    return *this;
}


/**
 * @brief Acumulador -=
 *
 * @param v
 */
template <class T>
vec3<T>& vec3<T>::operator -= ( const vec3<T> &v ) {
    this->x -= v.x;
    this->y -= v.y;
    this->z -= v.z;
    return *this;
}


/**
 * @brief Acumulador *=
 *
 * @param v
 */
template <class T>
vec3<T>& vec3<T>::operator *= ( const vec3<T> &v ) {
    this->x *= v.x;
    this->y *= v.y;
    this->z *= v.z;
    return *this;
}


/**
 * @brief Acumulador /=
 *
 * @param v
 */
template <class T>
vec3<T>& vec3<T>::operator /= ( const vec3<T> &v ) {
    this->x /= v.x;
    this->y /= v.y;
    this->z /= v.z;
    return *this;
}


/**
 * @brief Cross-product
 *
 * Computa o cross-product entre dois vetores e armazena neste
 *
 * @param v1
 * @param v2
 */
template <class T>
void vec3<T>::cross( const vec3<T> &v1, const vec3<T> &v2 ) {
    vec3<T> c;
    c.x = v1.y * v2.z - v1.z * v2.y;
    c.y = v1.z * v2.x - v1.x * v2.z;
    c.z = v1.x * v2.y - v1.y * v2.x;

    this->x = c.x;
    this->y = c.y;
    this->z = c.z;
}


/**
 * @brief Cross-product
 *
 * Computa o cross-product entre um vetor e este
 *
 * @param v
 */
template <class T>
void vec3<T>::cross( const vec3<T> &v ) {
    vec3<T> c;
    c.x = this->y * v.z - this->z * v.y;
    c.y = this->z * v.x - this->x * v.z;
    c.z = this->x * v.y - this->y * v.x;

    this->x = c.x;
    this->y = c.y;
    this->z = c.z;
}
